package cn.easyutil.util.javaUtil;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import com.itextpdf.text.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;

import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;

public class PDFUtil {

	/**
	 * PDF文件转PNG图片，全部页数
	 * 
	 * @param pdfInput
	 *            pdf输入流
	 * @param imageOut
	 *            输出流
	 * @param dpi
	 *            清晰度,默认300
	 */
	public static void pdfToImage(InputStream in, OutputStream imageOut, int dpi) {
		if(in == null){
			throw new RuntimeException("import of pdf must not be null");
		}
		PDDocument pdDocument = null;
		try {
			int count = 0;
			long start = System.currentTimeMillis();
			while (count == 0) {
				if(System.currentTimeMillis()-start > 3000){
					throw new RuntimeException("read InputStream timeout");
				}
				count = in.available();
			}
			byte[] but = new byte[count];
			@SuppressWarnings("unused")
			int length=0;
			while((length = in.read(but))!=-1){}
			pdDocument = PDDocument.load(but);
			PDFRenderer renderer = new PDFRenderer(pdDocument);
			/* dpi越大转换后越清晰，相对转换速度越慢 */
			PdfReader reader = new PdfReader(but);
			int pages = reader.getNumberOfPages();
			for (int i = 0; i < pages; i++) {
				BufferedImage image = renderer.renderImageWithDPI(i, dpi);
				ImageIO.write(image, "png", imageOut);
			}
			LoggerUtil.debug(PDFUtil.class, "pdf Conversion image success");
		} catch (IOException e) {
			LoggerUtil.error(PDFUtil.class, "pdf Conversion image failed");
			throw new RuntimeException(e);
		} finally {
			try {
				if(pdDocument!=null){
					pdDocument.close();
				}
				if(imageOut!=null){
					imageOut.close();
				}
				if(in != null){
					in.close();
				}
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}

	/**
	 * PDF文件转PNG图片，全部页数
	 * 
	 * @param pdfInput
	 *            pdf输入流
	 * @param imageOut
	 *            输出流
	 */
	public static void pdfToImage(String pdfPath, String imagePath) {
		try {
			pdfToImage(new FileInputStream(new File(pdfPath)), new FileOutputStream(new File(imagePath)), 300);
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}


	/**
	 * PDF文件转PNG图片，全部页数
	 * 
	 * @param pdfPath
	 *            pdf文件地址
	 * @param imagePath
	 *            输出目的地文件地址
	 */
	public static void pdfToImage(InputStream in, String imagePath) {
		if(!imagePath.endsWith(".png")){
			imagePath = imagePath+".png";
		}
		try {
			pdfToImage(in,new FileOutputStream(new File(imagePath)), 300);
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * PDF文件转PNG图片，全部页数
	 * 
	 * @param pdfPath
	 *            pdf文件地址
	 * @param response
	 *            输出流
	 * @param dpi
	 *            清晰度,默认300
	 */
	public static void pdfToImage(InputStream in, HttpServletResponse response, int dpi) {
		try {
			pdfToImage(in, response.getOutputStream(),dpi);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * PDF文件转PNG图片，全部页数
	 * 
	 * @param pdfPath
	 *            pdf文件地址
	 * @param response
	 *            输出流
	 * @param dpi
	 *            清晰度,默认300
	 */
	public static void pdfToImage(String pdfPath, HttpServletResponse response, int dpi) {
		try {
			pdfToImage(new FileInputStream(new File(pdfPath)), response, dpi);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	/**
	 * PDF文件转PNG图片，全部页数
	 * 
	 * @param pdfPath
	 *            pdf文件地址
	 * @param response
	 *            输出流
	 */
	public static void pdfToImage(InputStream in, HttpServletResponse response) {
		pdfToImage(in, response,300);
	}

	/**
	 * 图片转pdf
	 * 
	 * @param imagePath
	 *            图片地址
	 * @param pdfPath
	 *            转出地址
	 */
	public static void imageToPdf(String imagePath, String pdfPath) {
		if (!pdfPath.endsWith(".pdf")) {
			if (pdfPath.contains(".")) {
				pdfPath = pdfPath.substring(0, pdfPath.indexOf(".")) + ".pdf";
			} else {
				pdfPath = pdfPath + ".pdf";
			}
		}
		try {
			BufferedImage img = ImageIO.read(new File(imagePath));
			FileOutputStream fos = new FileOutputStream(pdfPath);
			Document doc = new Document(null, 0, 0, 0, 0);
			doc.setPageSize(new Rectangle(img.getWidth(), img.getHeight()));
			Image image = Image.getInstance(imagePath);
			float scalePercentage = (72 / 300f) * 100.0f;
			image.scalePercent(scalePercentage, scalePercentage);
			PdfWriter.getInstance(doc, fos);
			doc.open();
			doc.add(image);
			doc.close();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 往pdf的指定域字段上填充内容
	 * 
	 * @param pdfPath
	 *            想要填充的pdf模板路径
	 * @param outPath
	 *            填充后的pdf文件生成路径
	 * @param map
	 *            要填充的值 key:域字段 val:值
	 * @return
	 */
	public static void insertText(String pdfPath, String outPath, Map<String, Object> map) {
		if (StringUtil.isEmpty(map)) {
			throw new NullPointerException("filling data must not be null");
		}
		try {
			if (!outPath.endsWith(".pdf")) {
				if (outPath.contains(".")) {
					outPath = outPath.substring(0, outPath.indexOf(".")) + ".pdf";
				} else {
					outPath = outPath + ".pdf";
				}
			}
			InputStream in = new FileInputStream(new File(pdfPath));
			ByteArrayOutputStream out = (ByteArrayOutputStream) generate(new PdfReader(in), map);
			// 将pdf字节流输出到文件流
			OutputStream fos = new FileOutputStream(outPath);
			fos.write(out.toByteArray());
			fos.close();
			out.close();
			LoggerUtil.debug(PDFUtil.class, "PDF filling success");
		} catch (Exception e) {
			LoggerUtil.error(PDFUtil.class, "PDF filling failed");
			throw new RuntimeException(e);
		}
	}

	/**
	 * 将数据，填入pdf表单域
	 * 
	 */
	private static OutputStream generate(PdfReader template, Map<String, Object> data) {
		try {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			PdfStamper stamp = new PdfStamper(template, out);
			AcroFields form = stamp.getAcroFields();
			for (String key : data.keySet()) {
				String value = data.get(key).toString();
				form.setFieldProperty(key, "textfont", BaseFont.createFont(), null);
				form.setField(key, value);
			}
			stamp.setFormFlattening(true);
			stamp.close();
			template.close();
			return out;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static void main(String[] args) throws FileNotFoundException {
		pdfToImage(new FileInputStream(new File("D://www.pdf")), "D://ww-ong.png");
	}
}
